package CompositionToSequence;
use MassData qw(%BasicInfo %GAGInfo);
use List::Util qw[sum];
use Storable qw[dclone];
use Math::Combinatorics;
use Class::Struct;

## The input is a reference to an array of GAG objects
## The ouput is the reference with modification information updated.
## The interface should be frinedly to users while the details can be processed inside the module.

sub CompositionToSequence {
	
	#my ($modi_chain,$compo_ref) = @_;
	my $compo_ref = shift;
	my $current_pos = 0;
	my @counter = (0) x 2;
	my $candi;
  	our @composition = @{$compo_ref};
  	our $dp = sum(@composition[0..2]);
	
	our %MonoTable = %{$BasicInfo{'MonoTable'}};
	our %CompoundTable = %{$BasicInfo{'CompoundTable'}};
	
	my $modi_chain = CreateGAGChain($compo_ref);
	
	
	my $chain_ref = ModificationAlongSequence($current_pos,$modi_chain,$candi,\@counter);

	return $chain_ref;
		
}

sub CreateGAGChain {
	my $compo_ref =shift;
	my @gag_chain;
	for(my $i=0; $i<2*$dp-1; $i++){
		my @unit_pieces;
		if($i%4 == 0) {
			## HexA
			@unit_pieces = @{$GAGInfo{'HS'}->{'unit'}->[0]};
		} elsif($i%4==2) {
			## GlcN
			@unit_pieces = @{$GAGInfo{'HS'}->{'unit'}->[1]};	
		} elsif($i%2==1) {
			## Oxygen atom
			@unit_pieces = ($MonoTable{'O'});
		}
		if($i==0) { # The first ring is unsaturated.
			$unit_pieces[5] -= $MonoTable{'H'};	
		} elsif($i==2*$dp-2){
			$unit_pieces[1] += $MonoTable{'O'} + $MonoTable{'H'};
		}
		my $unit;
		$unit = MonoUnit->new(
			idx => $i,
			mass_piece => [@unit_pieces],
			modification	=> 0,
			fragment => UnitFrag->new(
				piece => [@unit_pieces],
				cleavage => UnitCleavage->new(
					begin => 0,
					end => 0,
					direction => 0
				)
			)
		);

		push @gag_chain, $unit;
	}
	return \@gag_chain;
}
sub ModificationAlongSequence {
	
	my ($index, $modi_chain, $candi, $count_info) = @_;
	my @patterns = @{$GAGInfo{'HS'}->{'modification'}->[($index%4)/2]};
	
	foreach my $pat (@patterns){
		## Copy the chain.
		my $temp_chain = dclone($modi_chain);

		## Calculate the number of modification on each unit.
		my $digit_count = length($pat);
		## Split digits
		my @modi_array = split //, $pat;

		## Temporay variable storing the total number of modifications.  
		my @temp = @$count_info;

		if($modi_array[0] == 1) {    # Acetation
			next if $count_info->[1] == $composition[4];
			## Update the temporary variable.
			$temp[0] += $digit_count - 1;  # Sulfate group
			$temp[1] += 1;  # Acetate group

			next if ($temp[0] > $composition[3]) || ($temp[1] > $composition[4]);

		} elsif($modi_array[0] != 1 && $modi_array[0] != 0) {
		
			$temp[0] += $digit_count;  # Sulfate groups

			next if $temp[0] > $composition[3];
			
		} 

		$temp_chain->[$index]->modification($pat) unless $pat==0;
		
		if($temp[0]==$composition[3] && $temp[1]==$composition[4]) {
			foreach my $unit (@$temp_chain){
				next if $unit->modification == 0;
				foreach my $i (split //,$unit->modification){
					$unit->fragment->piece->[2] = ($unit->mass_piece->[2] += $CompoundTable{'ac'}) if $i==1;
					$unit->fragment->piece->[$i] = ($unit->mass_piece->[$i] += $CompoundTable{'sg'}) if $i!=1;
				}
			}
			push @{$candi}, dclone($temp_chain);
			next;
		}
		
		next if ($index+2) > (2*$dp-2);
		
		$candi = ModificationAlongSequence($index+2,$temp_chain,$candi,\@temp);
	}
	return $candi;
}

1;
